import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
import re
from datetime import datetime
import os


def load_and_explore_data():
    """加载数据并进行初步探索"""
    print("=" * 60)
    print("开始加载数据...")

    # 检查文件是否存在
    if not os.path.exists('新浪财经历史分红数据.xlsx'):
        print("错误：文件 '新浪财经历史分红数据.xlsx' 不存在")
        return None

    try:
        # 读取Excel文件
        df = pd.read_excel('新浪财经历史分红数据.xlsx')
        print("数据加载成功！")

        # 输出数据形状
        print(f"数据形状: {df.shape} (行数: {df.shape[0]}, 列数: {df.shape[1]})")
        print("\n" + "=" * 60)

        return df
    except Exception as e:
        print(f"读取文件时出错: {e}")
        return None


def check_duplicates_and_preview(df):
    """检查重复值和数据预览"""
    print("1. 变量名称检查:")
    print(f"列名: {list(df.columns)}")
    print()

    print("2. 重复值检查:")
    # 检查整行重复
    duplicate_rows = df.duplicated().sum()
    print(f"整行重复数量: {duplicate_rows}")

    # 检查关键变量的重复值
    key_columns = ['代码', '简称']  # 根据实际列名调整
    for col in key_columns:
        if col in df.columns:
            duplicate_count = df[col].duplicated().sum()
            print(f"变量 '{col}' 的重复值数量: {duplicate_count}")

    print("\n3. 数据前五行:")
    pd.set_option('display.max_columns', None)  # 显示所有列
    print(df.head())

    print("\n4. 数据基本信息:")
    print(df.info())

    print("\n5. 数值型变量描述统计:")
    numerical_cols = df.select_dtypes(include=[np.number]).columns
    if len(numerical_cols) > 0:
        print(df[numerical_cols].describe())

    print("\n" + "=" * 60)


def clean_column_names(df):
    """清理列名"""
    print("清理列名...")

    # 创建列名映射字典
    new_columns = {}
    for col in df.columns:
        # 去除空格和特殊字符
        clean_col = re.sub(r'[\s\u3000]+', '', str(col))  # 去除空格和全角空格
        clean_col = clean_col.strip()
        new_columns[col] = clean_col

    df_clean = df.rename(columns=new_columns)
    print(f"清理后的列名: {list(df_clean.columns)}")

    return df_clean


def process_date_variables(df):
    """处理上市日期变量，提取年月日"""
    print("\n处理上市日期变量...")

    # 查找包含日期的列（根据实际列名调整）
    date_columns = [col for col in df.columns if '日期' in col or 'date' in col.lower()]

    if not date_columns:
        print("未找到明确的日期列，请手动指定日期列名")
        # 显示所有列名供选择
        print("可用列名:", list(df.columns))
        return df

    date_col = date_columns[0]
    print(f"找到日期列: {date_col}")

    # 复制原始数据
    df_processed = df.copy()

    # 处理日期格式
    df_processed[f'{date_col}_原值'] = df_processed[date_col]

    try:
        # 尝试多种日期格式转换
        df_processed[date_col] = pd.to_datetime(
            df_processed[date_col],
            errors='coerce',
            format='mixed'
        )

        # 提取年月日
        df_processed['上市年份'] = df_processed[date_col].dt.year
        df_processed['上市月份'] = df_processed[date_col].dt.month
        df_processed['上市日'] = df_processed[date_col].dt.day

        # 检查转换结果
        successful_conversions = df_processed[date_col].notna().sum()
        print(f"成功转换的日期数量: {successful_conversions}/{len(df_processed)}")

        # 显示日期处理结果
        date_sample = df_processed[['上市年份', '上市月份', '上市日']].head()
        print("日期提取结果示例:")
        print(date_sample)

    except Exception as e:
        print(f"日期处理出错: {e}")
        # 如果自动转换失败，尝试手动处理
        df_processed['上市年份'] = np.nan
        df_processed['上市月份'] = np.nan
        df_processed['上市日'] = np.nan

    return df_processed


def normalize_numerical_variables(df):
    """对数值型变量进行归一化处理"""
    print("\n开始数值型变量归一化处理...")

    # 根据提供的变量名查找对应的列
    target_variables = ['累计股息', '年均股息', '分红次数', '融资总额']

    # 查找实际存在的列
    existing_vars = []
    for var in target_variables:
        # 查找包含变量名的列
        matching_cols = [col for col in df.columns if var in col]
        if matching_cols:
            existing_vars.extend(matching_cols)

    if not existing_vars:
        print("未找到指定的数值型变量，可用数值型变量:")
        numerical_cols = df.select_dtypes(include=[np.number]).columns
        print(list(numerical_cols))
        return df, pd.DataFrame()

    print(f"将进行归一化的变量: {existing_vars}")

    # 检查数据有效性
    for var in existing_vars:
        if var in df.columns:
            print(f"{var} - 非空值数量: {df[var].notna().sum()}, 取值范围: [{df[var].min():.2f}, {df[var].max():.2f}]")

    # 创建归一化器
    scaler = MinMaxScaler()

    # 准备数据（处理缺失值）
    normalization_data = df[existing_vars].copy()

    # 填充缺失值（使用中位数）
    for col in existing_vars:
        if normalization_data[col].isna().any():
            median_val = normalization_data[col].median()
            normalization_data[col] = normalization_data[col].fillna(median_val)
            print(f"变量 {col} 的缺失值已用中位数 {median_val:.2f} 填充")

    # 进行归一化
    try:
        normalized_values = scaler.fit_transform(normalization_data[existing_vars])
        normalized_df = pd.DataFrame(
            normalized_values,
            columns=[f'{col}_归一化' for col in existing_vars],
            index=df.index
        )

        print("归一化完成！归一化后的统计信息:")
        print(normalized_df.describe())

        return df, normalized_df

    except Exception as e:
        print(f"归一化处理出错: {e}")
        return df, pd.DataFrame()


def main():
    """主函数"""
    print("新浪财经历史分红数据预处理")
    print("=" * 60)

    # 1. 加载数据
    df = load_and_explore_data()
    if df is None:
        return

    # 2. 检查重复值和预览数据
    check_duplicates_and_preview(df)

    # 3. 清理列名
    df_clean = clean_column_names(df)

    # 4. 处理上市日期
    df_processed = process_date_variables(df_clean)

    # 5. 数值型变量归一化
    df_final, normalized_df = normalize_numerical_variables(df_processed)

    # 6. 横向合并数据
    if not normalized_df.empty:
        df_combined = pd.concat([df_final, normalized_df], axis=1)
        print(f"\n合并后的数据形状: {df_combined.shape}")
    else:
        df_combined = df_final
        print("\n未进行归一化合并")

    # 7. 保存预处理后的数据
    output_filename = "新浪财经历史分红数据_预处理.xlsx"
    try:
        df_combined.to_excel(output_filename, index=False)
        print(f"\n预处理数据已保存至: {output_filename}")

        # 显示保存文件的信息
        file_size = os.path.getsize(output_filename) / 1024  # KB
        print(f"文件大小: {file_size:.2f} KB")
        print(f"最终数据形状: {df_combined.shape}")

        # 显示预处理后的数据前五行
        print("\n预处理后的数据前五行:")
        pd.set_option('display.width', None)
        pd.set_option('display.max_columns', None)
        print(df_combined.head())

    except Exception as e:
        print(f"保存文件时出错: {e}")

    print("\n" + "=" * 60)
    print("数据预处理完成！")


if __name__ == "__main__":
    main()